/*
 * Copyright 2003-2005 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

using System;

using BigEndianUnsignedByte = argot.common.BigEndianUnsignedByte;
using BigEndianUnsignedShort = argot.common.BigEndianUnsignedShort;
using Empty = argot.common.Empty;
using U8Ascii = argot.common.U8Ascii;
using MetaAbstract = argot.meta.MetaAbstract;
using MetaArray = argot.meta.MetaArray;
using MetaBasic = argot.meta.MetaBasic;
using MetaDefinition = argot.meta.MetaDefinition;
using MetaEncoding = argot.meta.MetaEncoding;
using MetaExpression = argot.meta.MetaExpression;
using MetaMap = argot.meta.MetaMap;
using MetaMarshaller = argot.meta.MetaMarshaller;
using MetaReference = argot.meta.MetaReference;
using MetaSequence = argot.meta.MetaSequence;

namespace argot
{
	
	/// <summary> 
	/// The CoreTypeMap is the basis for the type system.  It is a constrained
	/// set of objects which describe the structure of data.  All serial
	/// data must be able to be represented by this set of structures.
	/// </summary>
	public class TypeMapCore
	:ReferenceTypeMap
	{
		public static System.Collections.IList CoreIdentifiers
		{
			get
			{
				System.Collections.IList coreIds = new System.Collections.ArrayList();
				
				coreIds.Add((System.Int32) EMPTYID);
				coreIds.Add((System.Int32) U8BID);
				coreIds.Add((System.Int32) U16BID);
				coreIds.Add((System.Int32) BASICID);
				coreIds.Add((System.Int32) ABSTRACTID);
				coreIds.Add((System.Int32) MAP_ID);
				coreIds.Add((System.Int32) EXPRESSIONID);
				coreIds.Add((System.Int32) SEQUENCEID);
				coreIds.Add((System.Int32) REFERENCEID);
				coreIds.Add((System.Int32) NAMEID);
				coreIds.Add((System.Int32) ENCODEDID);
				coreIds.Add((System.Int32) ARRAYID);
				coreIds.Add((System.Int32) EXPRESSION_REFERENCE_ID);
				coreIds.Add((System.Int32) EXPRESSION_SEQUENCE_ID);
				coreIds.Add((System.Int32) EXPRESSION_ARRAY_ID);
				coreIds.Add((System.Int32) EXPRESSION_ENCODED_ID);
				coreIds.Add((System.Int32) DEFINITION_ID);
				coreIds.Add((System.Int32) DEFINITION_BASIC_ID);
				coreIds.Add((System.Int32) DEFINITION_MAP_ID);
				coreIds.Add((System.Int32) DEFINITION_SEQUENCE_ID);
				coreIds.Add((System.Int32) DEFINITION_ABSTRACT_ID);
				return coreIds;
			}
			
		}
		public static TypeMapCore _coreTypeMap;
		
		public static TypeMapCore GetCoreTypeMap(TypeLibrary library, TypeMap refMap)
		{
			return new TypeMapCore(library, refMap);
		}
		
		public static TypeMapCore GetCoreTypeMap(TypeLibrary library)
		{
			TypeMapCore refMap = new TypeMapCore(library, null);
			refMap.ReferenceMap = refMap;
			return refMap;
		}
		
		private TypeMapCore(TypeLibrary library, TypeMap refMap):base(library, refMap)
		{
			MapMeta(this, library);
		}
		
		public static void  MapMeta(TypeMap map, TypeLibrary library)
		{
			map.Map(EMPTYID, library.GetId(Empty.TYPENAME));
			map.Map(U8BID, library.GetId(BigEndianUnsignedByte.TYPENAME));
			map.Map(U16BID, library.GetId(BigEndianUnsignedShort.TYPENAME));
			map.Map(BASICID, library.GetId(MetaBasic.TYPENAME));
			map.Map(ABSTRACTID, library.GetId("meta.abstract"));
			map.Map(MAP_ID, library.GetId("meta.map"));
			map.Map(EXPRESSIONID, library.GetId("meta.expression"));
			map.Map(SEQUENCEID, library.GetId(MetaSequence.TYPENAME));
			map.Map(REFERENCEID, library.GetId(MetaReference.TYPENAME));
			map.Map(NAMEID, library.GetId("meta.name"));
			map.Map(ENCODEDID, library.GetId("meta.encoding"));
			map.Map(ARRAYID, library.GetId(MetaArray.TYPENAME));
			map.Map(EXPRESSION_REFERENCE_ID, library.GetId("meta.expression#reference"));
			map.Map(EXPRESSION_SEQUENCE_ID, library.GetId("meta.expression#sequence"));
			map.Map(EXPRESSION_ARRAY_ID, library.GetId("meta.expression#array"));
			map.Map(EXPRESSION_ENCODED_ID, library.GetId("meta.expression#encoding"));
			map.Map(DEFINITION_ID, library.GetId("meta.definition"));
			map.Map(DEFINITION_BASIC_ID, library.GetId("meta.definition#basic"));
			map.Map(DEFINITION_MAP_ID, library.GetId("meta.definition#map"));
			map.Map(DEFINITION_SEQUENCE_ID, library.GetId("meta.definition#sequence"));
			map.Map(DEFINITION_ABSTRACT_ID, library.GetId("meta.definition#abstract"));
		}
		
		public static void  LoadLibrary(TypeLibrary library)
		{
			// Register the basic types we need.
			// The core objects required are those objects which provide the ability to
			// read the structures registered to the type library later.  As these types
			// are not yet registered we need to build each structure up manually.

			// Register the empty type with the SystemLibrary if required.
			// 0 - empty - a basic type representing an empty value.
			//   - basic 0 0
			
			if (library.GetTypeState("empty") == TypeLibrary.TYPE_NOT_DEFINED)
			{
				library.Reserve("empty");
				library.Reserve("meta.basic");
				
				Empty te = new Empty();
				MetaDefinition emptyDef = new MetaBasic((sbyte) 0, (sbyte) 0);
				library.Register(Empty.TYPENAME, emptyDef, te, te, te.GetType());
			}
			
			// Register the u8b type with the SystemLibrary if required.
			// 1 - U8B - a basic type representing an unsigned 8bit big endian byte.
			//   - basic 8 0
			
			if (library.GetTypeState(BigEndianUnsignedByte.TYPENAME) == TypeLibrary.TYPE_NOT_DEFINED)
			{
				BigEndianUnsignedByte bbe = new BigEndianUnsignedByte();
				MetaDefinition u8def = new MetaBasic((sbyte) 8, (sbyte) 0);
				
				library.Register(BigEndianUnsignedByte.TYPENAME, u8def, bbe, bbe, null);
			}
			
			// Register the u16b type with the SystemLibrary if required.
			// 2 - U16B - a basic type of unsigned 16bit big endian integer.
			if (library.GetTypeState(BigEndianUnsignedShort.TYPENAME) == TypeLibrary.TYPE_NOT_DEFINED)
			{
				BigEndianUnsignedShort bbs = new BigEndianUnsignedShort();
				MetaDefinition u16def = new MetaBasic((sbyte) 16, (sbyte) 0);
				library.Register(BigEndianUnsignedShort.TYPENAME, u16def, bbs, bbs, null);
			}
			
			
			library.Reserve("meta.sequence");
			library.Reserve("meta.reference");
			
			MetaBasic tb = new MetaBasic((sbyte) 0, (sbyte) 0);
			MetaDefinition basicDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("u8"), "size"), 
					new MetaReference(library.GetId("u8"), "flags")
				}
			);
			library.Register(MetaBasic.TYPENAME, basicDef, tb, tb, tb.GetType());
			

			library.Reserve("meta.encoding");
			library.Reserve("meta.array");
			
			U8Ascii u8Ascii = new U8Ascii();
			
			MetaDefinition nameDef = new MetaSequence(
				new MetaExpression[]{
					new MetaEncoding(
						new MetaArray(
							new MetaReference(library.GetId("u8"), "size"), 
							new MetaReference(library.GetId("u8"), "data")), 
					"ISO646-US")
				}
			);		
			library.Register("meta.name", nameDef, u8Ascii, u8Ascii, null);
	
			
			MetaAbstract metaAbstract = new MetaAbstract();
			MetaDefinition abstractDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("empty"), "abstract")
				}
			);
			library.Register("meta.abstract", abstractDef, metaAbstract, metaAbstract, metaAbstract.GetType());
			

			MetaMap metaMap = new MetaMap(0, 0);
			
			MetaDefinition metaMapDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("u16"), "abstract"), 
					new MetaReference(library.GetId("u16"), "concrete")
				}
			);
			library.Register("meta.map", metaMapDef, metaMap, metaMap, metaMap.GetType());
					
			
			MetaDefinition exprDef = new MetaAbstract();	
			library.Register("meta.expression", exprDef, new MetaMarshaller(), new MetaMarshaller(), null);
			

			MetaEncoding metaEncoding = new MetaEncoding(null, null);
			MetaDefinition encodingDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("meta.expression"), "data"), 
					new MetaReference(library.GetId("meta.name"), "encoding")
				}
			);
			library.Register("meta.encoding", encodingDef, metaEncoding, metaEncoding, metaEncoding.GetType());
			

			MetaReference tr = new MetaReference(- 1, "");
			
			MetaDefinition refDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("u16"), "type"), 
					new MetaReference(library.GetId("meta.name"), "name")
				}
			);
			library.Register("meta.reference", refDef, tr, tr, tr.GetType());
			
			
			MetaSequence ts = new MetaSequence((MetaExpression[]) null);
			
			MetaDefinition seqDef = new MetaSequence(
				new MetaExpression[]{new MetaArray(
					new MetaReference(library.GetId("u8"), "size"), 
					new MetaReference(library.GetId("meta.expression"), "type")
				)}
			);
			library.Register("meta.sequence", seqDef, ts, ts, ts.GetType());
			

			MetaArray ta = new MetaArray(null, null);
			
			MetaDefinition arrayDef = new MetaSequence(
				new MetaExpression[]{
					new MetaReference(library.GetId("meta.expression"), "size"), 
					new MetaReference(library.GetId("meta.expression"), "type")
				}
			);
			library.Register("meta.array", arrayDef, ta, ta, ta.GetType());
			

			MetaMap exprRefDef = new MetaMap(library.GetId("meta.expression"), library.GetId("meta.reference"));
			library.Register("meta.expression#reference", exprRefDef, new MetaMarshaller(), new MetaMarshaller(), null);

			MetaMap exprExpSeq = new MetaMap(library.GetId("meta.expression"), library.GetId("meta.sequence"));
			library.Register("meta.expression#sequence", exprExpSeq, new MetaMarshaller(), new MetaMarshaller(), null);

			MetaMap exprDefArr = new MetaMap(library.GetId("meta.expression"), library.GetId("meta.array"));
			library.Register("meta.expression#array", exprDefArr, new MetaMarshaller(), new MetaMarshaller(), null);

			MetaMap exprDefEnc = new MetaMap(library.GetId("meta.expression"), library.GetId("meta.encoding"));
			library.Register("meta.expression#encoding", exprDefEnc, new MetaMarshaller(), new MetaMarshaller(), null);
			
			MetaAbstract mm = new MetaAbstract();
			library.Register("meta.definition", mm, new MetaMarshaller(), new MetaMarshaller(), null);
			
			MetaMap mmbasic = new MetaMap(library.GetId("meta.definition"), library.GetId("meta.basic"));
			library.Register("meta.definition#basic", mmbasic, new MetaMarshaller(), new MetaMarshaller(), null);
			
			MetaMap exprDefSeq = new MetaMap(library.GetId("meta.definition"), library.GetId("meta.sequence"));
			library.Register("meta.definition#sequence", exprDefSeq, new MetaMarshaller(), new MetaMarshaller(), null);
			
			MetaMap exprDefMap = new MetaMap(library.GetId("meta.definition"), library.GetId("meta.map"));
			library.Register("meta.definition#map", exprDefMap, new MetaMarshaller(), new MetaMarshaller(), null);

			MetaMap exprDefAbs = new MetaMap(library.GetId("meta.definition"), library.GetId("meta.abstract"));
			library.Register("meta.definition#abstract", exprDefAbs, new MetaMarshaller(), new MetaMarshaller(), null);
			
			MetaMap exprDefRef = new MetaMap(library.GetId("meta.definition"), library.GetId("meta.reference"));
			library.Register("meta.definition#reference", exprDefRef, new MetaMarshaller(), new MetaMarshaller(), null);
		}
		
		public static int EMPTYID = 1;
		public static int U8BID = 2;
		public static int U16BID = 3;
		public static int BASICID = 4;
		public static int ABSTRACTID = 5;
		public static int MAP_ID = 6;
		public static int EXPRESSIONID = 7;
		public static int SEQUENCEID = 8;
		public static int REFERENCEID = 9;
		public static int NAMEID = 10;
		public static int ENCODEDID = 11;
		public static int ARRAYID = 12;
		public static int EXPRESSION_REFERENCE_ID = 13;
		public static int EXPRESSION_SEQUENCE_ID = 14;
		public static int EXPRESSION_ARRAY_ID = 15;
		public static int EXPRESSION_ENCODED_ID = 16;
		public static int DEFINITION_ID = 17;
		public static int DEFINITION_BASIC_ID = 18;
		public static int DEFINITION_MAP_ID = 19;
		public static int DEFINITION_SEQUENCE_ID = 20;
		public static int DEFINITION_ABSTRACT_ID = 21;
	}
}